package com.ifp.core.log;

import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.ifp.core.base.Constants;
import com.ifp.core.base.SystemConf;
import com.ifp.core.data.DataMap;
import com.ifp.core.data.SessionElement;
import com.ifp.core.generator.IKeyGenerator;
import com.ifp.core.monitor.MonitorFlumeSample;
import com.ifp.core.monitor.MonitorManager;
import com.ifp.core.monitor.RequestInfo;
import com.ifp.core.monitor.RequestMap;
import com.ifp.core.session.IFPSession;
import com.ifp.core.session.IFPSessionManager;
import com.ifp.core.session.SessionManager;
import com.ifp.core.util.IpUtils;
import com.ifp.core.util.SpringContextsUtil;
import com.ifp.core.util.StringUtil;

/**
 * @author mogs 灭霸 2018-10-30 add @Lazy(false)
 */
public class LogHandle implements ILogHandle {
    private static final String CLIENT = "CLIENT";
    /**
     * 用于存放贯穿整个请求周期的线程日志
     */
    private ThreadLocal<LogThread> tl = new ThreadLocal<LogThread>();
    /**
     * 用于存放贯穿整个请求周期的数据，key需要带上前缀，避免重复。
     */
    private ThreadLocal<Map<String, Object>> tlTemp = new ThreadLocal<Map<String, Object>>();
    @Autowired
    @Qualifier("systemConf")
    private SystemConf systemConf;
    /**
     * 应用名称
     */
    private String appName;
    /**
     * IDC数据中心机房编号在applicationContext.xml配置
     */
    private String idcId = "IDC001";
    /**
     * QPS并发量统计时间间隔在applicationContext.xml配置
     */
    private int stainQPS = 10000;
    /**
     * 采样周期，单位毫秒，默认5秒
     */
    private int samplePeriod = 100;
    /**
     * 样本容量
     */
    private int sampleNum = 0;
    /**
     * 样本计数器
     */
    private AtomicInteger sampleCount = new AtomicInteger(0);
    /**
     * 请求样本
     */
    private MonitorFlumeSample maxRequestSample;
    /**
     * 服务样本集合
     */
    private Map<String, MonitorFlumeSample> maxSvcSamples;
    /**
     * 组件样本集合
     */
    private Map<String, MonitorFlumeSample> maxCompSamples;
    private boolean compress = false;
    /**
     * 打印远程调用开关
     */
    private boolean printRemote = false;
    /**
     * 简化服务调用信息开关
     */
    private boolean simplifiedSvcInfo = true;
    /**
     * 数据库服务信息开关
     */
    private boolean printDBSvcInfo;
    /**
     * 外联系统调用信息开关
     */
    private boolean printSISvcInfo;
    /**
     * RPC服务调用信息开关
     */
    private boolean printRPCSvcInfo;
    /**
     * 缓存服务调用信息开关
     */
    private boolean printCacheSvcInfo;
    /**
     * flume组装、输出开关
     */
    private boolean disable = true;
    /**
     * 作为SESSION初始化开关，和sessionGroup作用不一样；
     */
    private boolean printInitSessionInfo = true;
    /**
     * 如果分组不为空字符串，则开启session监控
     */
    private String sessionGroup = "";

    /**
     * session以存活时间升序排列
     */
    private final Comparator<IFPSession> sessionComparator = new Comparator<IFPSession>() {

        @Override
        public int compare(IFPSession o1, IFPSession o2) {
            Long rt = (o1.getLastAccessTime() - o1.getCreateTime()) - (o2.getLastAccessTime() - o2.getCreateTime());
            if (rt > 0) {
                return 1;
            } else if (rt < 0) {
                return -1;
            } else {
                return 0;
            }
        }

    };
    /**
     * 全局ID产生器
     */
    private IKeyGenerator reqIdGenerator;

    /**
     * 服务映射，组件映射集合
     */
    private Map<String, String> serviceNameMap, actionNameMap, serviceDescMap, actionDescMap;

    /**
     * 初始化
     * 
     * @return
     */
    @Override
    public LogThread init() {
        LogThread logThread = new LogThread();
        logThread.setRootId(generateLogThreadId());
        logThread.setCurrentId(logThread.getRootId());
        tl.set(logThread);
        tlTemp.set(new HashMap<String, Object>(0));
        return logThread;
    }

    /**
     * 初始化子线程
     * 
     * @param parentLogThread
     * @return
     */
    @Override
    public LogThread init(LogThread parentLogThread) {
        tlTemp.set(new HashMap<String, Object>(0));
        if (null != parentLogThread) {
            LogThread logThread = new LogThread();
            String currentNumber = parentLogThread.getNextNumber();
            logThread.setCurrentId(parentLogThread.getCurrentId() + "." + currentNumber);
            logThread.setRootId(parentLogThread.getRootId());
            tl.set(logThread);
            return logThread;
        }

        return null;
    }

    /**
     * 销毁线程变量
     */
    @Override
    public void destroy() {
        tl.remove();
        tlTemp.remove();
    }

    /**
     * 存放数据
     * 
     * @param key
     * @param value
     */
    public void putTempData(String key, Object value) {
        tlTemp.get().put(key, value);
    }

    /**
     * 获取数据
     * 
     * @param key
     * @return
     */
    public Object getTempData(String key) {
        return tlTemp.get().get(key);
    }

    /**
     * 取得日志前缀
     * 
     * @param module
     * @param message
     * @return
     */
    @Override
    public String getLogHead(String module, String message) {
        StringBuffer headString = new StringBuffer(module);
        LogThread logThread = getLogThread();
        if (null != logThread) {
            headString.append(" ").append(logThread.getCurrentId());
            if (getFlumeLogInf() != null) {
                headString.append(" ").append(getFlumeLogInf().getFlumeReqid());
            }
            if (null != logThread.getInfo()) {
                headString.append("[").append(logThread.getInfo()).append("]");
            }
        }

        headString.append(" - ").append(message);
        return headString.toString();
    }

    /**
     * 设置指定域信息
     * 
     * @param map
     */
    @Override
    public void setFieldInfo(Map<String, String> map) {
        if (null != map) {
            StringBuffer info = new StringBuffer();
            String logFields = (String)systemConf.getConfMap().get("logField");
            if (null != logFields && !"".equals(logFields)) {
                StringTokenizer logFieldArr = new StringTokenizer(logFields, "|");
                while (logFieldArr.hasMoreElements()) {
                    String logField = logFieldArr.nextToken();
                    if (map.containsKey(logField)) {
                        info.append(Constants.OR).append(map.get(logField));
                    } else {
                        info.append("|NA");
                    }
                }
                getLogThread().setFieldInfo(info.toString());
            }
        }
    }

    /**
     * 取得指定域信息
     * 
     * @return
     */
    @Override
    public String getFieldInfo() {
        return getLogThread().getFieldInfo();
    }

    /**
     * 设置附加信息
     * 
     * @param info
     */
    @Override
    public void setInfo(String info) {
        getLogThread().setInfo(info);
    }

    /**
     * 取得附加信息
     * 
     * @return
     */
    @Override
    public String getInfo() {
        return getLogThread().getInfo();
    }

    /**
     * 取得子线程的日志信息
     * 
     * @param parentLogThread
     * @return
     */
    @Override
    public LogThread getLogThread(LogThread parentLogThread) {
        if (null != parentLogThread) {
            LogThread logThread = tl.get();
            if (null == logThread) {
                logThread = init(parentLogThread);
            }

            return logThread;
        }

        return null;
    }

    /**
     * 取得当前线程的日志信息
     * 
     * @return
     */
    @Override
    public LogThread getLogThread() {
        LogThread logThread = tl.get();
        if (null == logThread) {
            logThread = init();
        }

        return logThread;
    }

    /**
     * 取得线程唯一标识
     * 
     * @return
     */
    private String generateLogThreadId() {
        Map confMap = systemConf.getConfMap();
        StringBuffer sb = new StringBuffer();
        if (null != confMap) {
            // 取得机器标识
            String appCode = (String)confMap.get("appCode");
            if (null != appCode) {
                // 增加下划线，方便未来作为分隔符，取得应用名称 wangzj@belink.com
                return sb.append(appCode).append("-").append(String.valueOf(System.currentTimeMillis()))
                    .append(StringUtil.generateRandomString(7)).toString();
            }
        }

        return sb.append(String.valueOf(System.currentTimeMillis())).append(StringUtil.generateRandomString(7))
            .toString();
    }

    /**
     * 取得调用ID
     * 
     * @return
     */
    private String generateCallId() {
        Map confMap = systemConf.getConfMap();
        StringBuffer sb = new StringBuffer();
        if (null != confMap) {
            // 取得机器标识
            String appCode = (String)confMap.get("appCode");
            if (null != appCode) {
                // 增加下划线，方便未来作为分隔符，取得应用名称 wangzj@belink.com
                return sb.append(idcId).append("-").append(IpUtils.getHostAddress()).append("-").append(appCode)
                    .append("-").append(String.valueOf(System.currentTimeMillis()))
                    .append(StringUtil.generateRandomString(7)).toString();
            }
        }

        return sb.append(idcId).append("-").append(IpUtils.getHostAddress()).append("-")
            .append(String.valueOf(System.currentTimeMillis())).append(StringUtil.generateRandomString(7)).toString();
    }

    /**
     * 设置FlumeLog参数
     * 
     * @param
     * @throws UnknownHostException
     */
    public void setFlumeLogInf(String flumeSessionId, String flumeServiceId, String flumeReqId, String flumeCid,
        String flumePid, String flumeReqIp, Long startTime) {
        if (!StringUtil.hasText(flumeReqId)) {
            flumeReqId = getFlumeLogReqId();
        }
        if (!StringUtil.hasText(flumeCid)) {
            flumeCid = getFlumeLogCid();
        }
        FlumeLogInf flumeLogInf = new FlumeLogInf();
        flumeLogInf.setFlumeSessionId(flumeSessionId);
        flumeLogInf.setFlumeServiceId(flumeServiceId);
        flumeLogInf.setFlumeReqid(flumeReqId);
        flumeLogInf.setFlumePid(flumePid);
        flumeLogInf.setFlumeCid(flumeCid);
        flumeLogInf.setFlumeSerStTime(startTime);
        flumeLogInf.setFlumeReqIP(flumeReqIp);

        setFlumeLogInf(flumeLogInf);
    }

    public void setFlumeLogInf(FlumeLogInf flumeLogInf) {
        // 注意：当消费者、提供者为同一工程时，消费者正好调到本系统的服务时，会沿用当前线程，而不会新建线程，不使用List<FlumeLogInf>的话会导致日志信息覆盖
        // （dubbo默认配置时如果发现是本地提供的的服务则直接使用而不会走dubbo协议）
        List<FlumeLogInf> flumeLogInfList = getLogThread().getFlumeLogInfList();
        if (flumeLogInfList == null) {
            // 如果是dubbo服务调用则为非空
            flumeLogInfList = new ArrayList<FlumeLogInf>();
        }
        flumeLogInfList.add(flumeLogInf);
        getLogThread().setFlumeLogInfList(flumeLogInfList);
    }

    /**
     * 打印flumeLogInfo 记录service信息
     * 格式如下：reqip|userid|sessionId|reqid|cId|pid|服务Id|服务开始时间|服务结束时间####组件名称|组件开始时间#组件2名称|组件2开始时间
     * 
     * @param serviceStartTime： 服务开始时间
     * @return
     */
    public void logFlumeService() {
        if (!this.isDisable()) {
            // 服务的结束时间
            Long serviceEndTime = System.currentTimeMillis();
            LogThread logThread = getLogThread();
            List<FlumeLogInf> flumeLogInfList = logThread.getFlumeLogInfList();
            if (flumeLogInfList.size() > 0) {
                FlumeLogInf flumeLogInf = flumeLogInfList.get(flumeLogInfList.size() - 1);
                // 组装日志
                StringBuffer sb = new StringBuffer();
                if (simplifiedSvcInfo) {
                    // reqip 请求ip
                    sb.append(flumeLogInf.getFlumeReqIP()).append(Constants.OR)
                        // userid
                        .append(null == flumeLogInf.getFlumeUserId() ? "" : flumeLogInf.getFlumeUserId())
                        .append(Constants.OR)
                        // sessionid
                        .append(null == flumeLogInf.getFlumeSessionId() ? "" : flumeLogInf.getFlumeSessionId())
                        .append(Constants.OR)
                        // appID
                        .append(getAppName()).append(Constants.OR).append(IpUtils.getHostAddress()).append(Constants.OR)
                        .append(idcId).append(Constants.OR)
                        // reqId 请求id
                        .append(flumeLogInf.getFlumeReqid()).append(Constants.OR)
                        // cId 当前日志id
                        .append(flumeLogInf.getFlumeCid()).append(Constants.OR)
                        // pId 父日志id
                        .append(null == flumeLogInf.getFlumePid() ? "" : flumeLogInf.getFlumePid()).append(Constants.OR)
                        // 服务Id
                        .append(null == serviceNameMap.get(flumeLogInf.getFlumeServiceId())
                            ? flumeLogInf.getFlumeServiceId() : serviceNameMap.get(flumeLogInf.getFlumeServiceId()))
                        .append(Constants.OR)
                        // 服务开始时间
                        .append(flumeLogInf.getFlumeSerStTime()).append(Constants.OR)
                        // 服务响应时间
                        .append(serviceEndTime - flumeLogInf.getFlumeSerStTime())
                        // 服务类型
                        .append(Constants.OR).append(flumeLogInf.getType())
                        // 无组件信息
                        .append("##");

                    // 打印日志
                    logFlume(Trace.MODULE_FLUME_NORMAL, Trace.LEVEL_F_STAT, "4", sb.toString());
                } else {
                    // reqip 请求ip
                    sb.append(flumeLogInf.getFlumeReqIP()).append(Constants.OR)
                        // userid
                        .append(null == flumeLogInf.getFlumeUserId() ? "" : flumeLogInf.getFlumeUserId())
                        .append(Constants.OR)
                        // sessionid
                        .append(null == flumeLogInf.getFlumeSessionId() ? "" : flumeLogInf.getFlumeSessionId())
                        .append(Constants.OR)
                        // appID
                        .append(getAppName()).append(Constants.OR)
                        // reqId 请求id
                        .append(flumeLogInf.getFlumeReqid()).append(Constants.OR)
                        // cId 当前日志id
                        .append(flumeLogInf.getFlumeCid()).append(Constants.OR)
                        // pId 父日志id
                        .append(null == flumeLogInf.getFlumePid() ? "" : flumeLogInf.getFlumePid()).append(Constants.OR)
                        // 服务Id
                        .append(null == serviceNameMap.get(flumeLogInf.getFlumeServiceId())
                            ? flumeLogInf.getFlumeServiceId() : serviceNameMap.get(flumeLogInf.getFlumeServiceId()))
                        .append(Constants.OR)
                        // 服务开始时间
                        .append(flumeLogInf.getFlumeSerStTime()).append(Constants.OR)
                        // 服务结束时间
                        .append(serviceEndTime)
                        // 服务类型
                        .append(Constants.OR).append(flumeLogInf.getType())
                        // logThread.getFlumeComInf()的格式为： #组件名称|组件开始时间，所以服务和组件信息用“####”分隔的
                        .append("###")
                        // 该服务下的所有组件信息 注：组件的结束时间是下一个组件的开始时间，startAction的开始时间是服务的开始时间，endAction的结束时间为服务的结束时间
                        .append(flumeLogInf.getFlumeComInf());

                    // 打印日志
                    logFlume(Trace.MODULE_FLUME_NORMAL, Trace.LEVEL_F_NORMAL, "0", sb.toString());
                }
            }
        }
    }

    /**
     * 打印数据库操作服务
     * 
     * @param tables
     * @param db
     * @param ip
     * @param idc
     * @param startTime
     */
    public void logFlumeDBService(String tables, String db, String ip, String idc, Long startTime) {
        if (this.printDBSvcInfo) {
            logFlumeExtService("DB", tables, db, ip, idc, startTime, null);
        }
    }

    /**
     * 打印数据库调用异常信息
     * 
     * @param tables
     * @param db
     * @param ip
     * @param idc
     * @param startTime
     * @param t
     */
    public void logFlumeDBSvcEx(String tables, String db, String ip, String idc, Long startTime, Throwable t) {
        if (this.printDBSvcInfo) {
            logFlumeExtSvcEx("DB", tables, db, ip, idc, startTime, null, t);
        }
    }

    /**
     * 打印通讯操作服务
     * 
     * @param tables
     * @param db
     * @param ip
     * @param idc
     * @param startTime
     * @param cid
     */
    public void logFlumeSIService(String tranCode, String chanId, String ip, String client, Long startTime,
        String cid) {
        if (this.printSISvcInfo) {
            logFlumeExtService("SI", tranCode, chanId, ip, client, startTime, cid);
        }
    }

    /**
     * 打印通讯异常信息
     * 
     * @param tranCode
     * @param chanId
     * @param ip
     * @param client
     * @param startTime
     * @param cid
     * @param t
     */
    public void logFlumeSISvcEx(String tranCode, String chanId, String ip, String client, Long startTime, String cid,
        Throwable t) {

        if (this.printSISvcInfo) {
            logFlumeExtSvcEx("SI", tranCode, chanId, ip, client, startTime, cid, t);
        }

    }

    /**
     * 打印RPC调用方法
     * 
     * @param compId
     * @param appId
     * @param ip
     * @param idc
     * @param startTime
     */
    public void logFlumeRPCService(String compId, String appId, String ip, String idc, Long startTime, String cid) {
        if (this.printRPCSvcInfo) {
            logFlumeExtService("RPC", compId, appId, ip, idc, startTime, cid);
        }
    }

    /**
     * 打印RPC调用异常信息
     * 
     * @param compId
     * @param appId
     * @param ip
     * @param idc
     * @param startTime
     * @param t
     */
    public void logFlumeRPCSvcEx(String compId, String appId, String ip, String idc, Long startTime, String cid,
        Throwable t) {
        if (this.printRPCSvcInfo) {
            logFlumeExtSvcEx("RPC", compId, appId, ip, idc, startTime, cid, t);
        }
    }

    /**
     * 打印缓存操作服务
     * 
     * @param method
     * @param appId
     * @param ip
     * @param idc
     * @param startTime
     */
    public void logFlumeCacheSvc(String method, String appId, String ip, String idc, Long startTime) {
        if (this.printCacheSvcInfo) {
            logFlumeExtService("CACHE", method, appId, ip, idc, startTime, null);
        }
    }

    /**
     * 打印缓存操作异常信息
     * 
     * @param tables
     * @param db
     * @param ip
     * @param idc
     * @param startTime
     * @param t
     */
    public void logFlumeCacheSvcEx(String tables, String db, String ip, String idc, Long startTime, Throwable t) {
        if (this.printCacheSvcInfo) {
            logFlumeExtSvcEx("CACHE", tables, db, ip, idc, startTime, null, t);
        }
    }

    /**
     * 打印flume的外部服务调用信息，比如DB\Redis\MQ\SI
     * 
     * @param type
     * @param svcId
     * @param appId
     * @param ip
     * @param idc
     * @param startTime
     * @param cid 如果为空则自己生成cid
     * @return cid
     */
    private String logFlumeExtService(String type, String svcId, String appId, String ip, String idc, Long startTime,
        String cid) {
        if (this.disable) {
            return "";
        }
        if (!StringUtil.hasText(appId)) {
            appId = getAppName();
        }
        if (!StringUtil.hasText(ip)) {
            ip = IpUtils.getHostAddress();
        }
        if (!StringUtil.hasText(idc)) {
            idc = idcId;
        }
        String newCid = cid;
        if (!StringUtil.hasText(newCid)) {
            newCid = getCallId();
        }
        // 服务的结束时间
        Long serviceEndTime = System.currentTimeMillis();
        LogThread logThread = getLogThread();
        List<FlumeLogInf> flumeLogInfList = logThread.getFlumeLogInfList();
        if (flumeLogInfList.size() > 0) {
            FlumeLogInf flumeLogInf = flumeLogInfList.get(flumeLogInfList.size() - 1);
            // 组装日志
            StringBuffer sb = new StringBuffer();
            // reqip 请求ip
            sb.append(IpUtils.getHostAddress()).append(Constants.OR)
                // userid
                .append(null == flumeLogInf.getFlumeUserId() ? "" : flumeLogInf.getFlumeUserId()).append(Constants.OR)
                // sessionid
                .append(null == flumeLogInf.getFlumeSessionId() ? "" : flumeLogInf.getFlumeSessionId())
                .append(Constants.OR)
                // appID
                .append(appId).append(Constants.OR).append(ip).append(Constants.OR).append(idc).append(Constants.OR)
                // reqId 请求id
                .append(flumeLogInf.getFlumeReqid()).append(Constants.OR).append(newCid).append(Constants.OR)
                // cId 当前日志id
                // pId 父日志id
                .append(flumeLogInf.getFlumeCid()).append(Constants.OR)
                // 服务Id
                .append(svcId).append(Constants.OR)
                // 服务开始时间
                .append(startTime).append(Constants.OR)
                // 服务响应时间
                .append(serviceEndTime - startTime)
                // 服务类型
                .append(Constants.OR).append(type)
                // 无组件信息
                .append("##");

            // 打印日志
            logFlume(Trace.MODULE_FLUME_NORMAL, Trace.LEVEL_F_STAT, "4", sb.toString());
        }
        return newCid;
    }

    /**
     * 打印外部调用服务的服务信息+异常信息
     * 
     * @param type
     * @param svcId
     * @param appId
     * @param ip
     * @param idc
     * @param startTime
     * @param t
     */
    private void logFlumeExtSvcEx(String type, String svcId, String appId, String ip, String idc, Long startTime,
        String cid, Throwable t) {
        if (this.disable) {
            return;
        }
        if (!StringUtil.hasText(appId)) {
            appId = getAppName();
        }
        if (!StringUtil.hasText(ip)) {
            ip = IpUtils.getHostAddress();
        }
        if (!StringUtil.hasText(idc)) {
            idc = idcId;
        }
        String newCid = cid;
        if (!StringUtil.hasText(newCid)) {
            newCid = getCallId();
        }
        // 服务的结束时间
        Long serviceEndTime = System.currentTimeMillis();
        LogThread logThread = getLogThread();
        List<FlumeLogInf> flumeLogInfList = logThread.getFlumeLogInfList();
        if (flumeLogInfList.size() > 0) {
            FlumeLogInf flumeLogInf = flumeLogInfList.get(flumeLogInfList.size() - 1);
            // 组装日志
            StringBuffer sb = new StringBuffer();
            if (this.printDBSvcInfo) {
                // reqip 请求ip
                sb.append(IpUtils.getHostAddress()).append(Constants.OR)
                    // userid
                    .append(null == flumeLogInf.getFlumeUserId() ? "" : flumeLogInf.getFlumeUserId())
                    .append(Constants.OR)
                    // sessionid
                    .append(null == flumeLogInf.getFlumeSessionId() ? "" : flumeLogInf.getFlumeSessionId())
                    .append(Constants.OR)
                    // appID
                    .append(appId).append(Constants.OR).append(ip).append(Constants.OR).append(idc).append(Constants.OR)
                    // reqId 请求id
                    .append(flumeLogInf.getFlumeReqid()).append(Constants.OR)
                    // cId 当前日志id
                    .append(newCid).append(Constants.OR)
                    // pId 父日志id
                    .append(flumeLogInf.getFlumeCid()).append(Constants.OR)
                    // 服务Id
                    .append(svcId).append(Constants.OR)
                    // 服务开始时间
                    .append(startTime).append(Constants.OR)
                    // 服务响应时间
                    .append(serviceEndTime - startTime).append(Constants.OR).append(type)
                    // 服务类型
                    // 无组件信息
                    .append("##");

                // 打印日志
                logFlume(Trace.MODULE_FLUME_NORMAL, Trace.LEVEL_F_STAT, "4", sb.toString());

                // 继续打印异常日志
                StringBuilder errMSg = new StringBuilder(t.toString());
                StackTraceElement[] stackTrace = t.getStackTrace();
                for (int i = 0; i < stackTrace.length; i++) {
                    errMSg.append("\n").append(stackTrace[i].toString());
                }
                sb.delete(0, sb.length());
                sb.append(flumeLogInf.getFlumeReqid()).append(Constants.OR).append(newCid).append(Constants.OR)
                    .append(flumeLogInf.getFlumeCid()).append(Constants.OR).append(svcId).append(Constants.OR)
                    .append(errMSg).append("##");
                this.logFlume(Trace.LEVEL_F_ERROR, null, sb.toString());
            }
        }
    }

    /**
     * print monitor initial data,required appName & serviceNameMap & actionNameMap
     */
    public void logFlumeInitData() {
        if (!isDisable()) {
            if (!StringUtil.hasText(appName) || serviceNameMap == null || actionNameMap == null) {
                return;
            }
            StringBuffer sb = new StringBuffer();
            // 1|应用ID|应用名|IP|IDC####服务ID|服务别名|服务名#服务2...##组件ID|组件别名|组件名#组件2...
            // 目前无法获取名称
            sb.append(getAppName()).append(Constants.OR).append(getAppDesc()).append(Constants.OR)
                .append(IpUtils.getHostAddress()).append(Constants.OR).append(getIdcId()).append("##").append("##");
            for (String svcName : serviceNameMap.keySet()) {
                sb.append(svcName).append(Constants.OR).append(serviceNameMap.get(svcName)).append(Constants.OR)
                    .append(StringUtil.hasText(serviceDescMap.get(svcName)) ? serviceDescMap.get(svcName) : "")
                    .append("#");
            }
            if (serviceNameMap != null && serviceNameMap.size() > 0) {
                sb.deleteCharAt(sb.length() - 1);
            } else {
                if (actionNameMap.size() == 0) {
                    sb.delete(sb.length() - 2, sb.length());
                    logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_INIT, "1", sb.toString());
                    return;
                }
            }
            sb.append("##");
            for (String actName : actionNameMap.keySet()) {
                sb.append(actName).append(Constants.OR).append(actionNameMap.get(actName)).append(Constants.OR)
                    .append(StringUtil.hasText(actionDescMap.get(actName)) ? actionDescMap.get(actName) : "")
                    .append("#");
            }
            if (actionNameMap != null && actionNameMap.size() > 0) {
                sb.deleteCharAt(sb.length() - 1);
            }
            logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_INIT, "1", sb.toString());
        }
    }

    private String getAppDesc() {
        String desc = (String)systemConf.getConfMap().get("appDesc");
        return StringUtil.hasText(desc) ? desc : "";
    }

    /**
     * 仅打印应用主机信息，作为初始化信息
     */
    public void logFlumeAppHost() {
        if (!isDisable()) {
            if (!StringUtil.hasText(appName)) {
                return;
            }
            StringBuffer sb = new StringBuffer();
            // 2|应用ID|应用名|IP|IDC##
            // 目前无法获取名称
            sb.append(getAppName()).append(Constants.OR).append("").append(Constants.OR)
                .append(IpUtils.getHostAddress()).append(Constants.OR).append(getIdcId()).append("##");
            logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_INIT, "2", sb.toString());
        }
    }

    /**
     * 打印远程调用时的记录点
     * 
     * @param rc
     */
    public void logFlumeRemote(RemoteCallInfo rc) {
        if (!isDisable()) {
            if (!printRemote || null == rc || getLogThread() == null
                || getLogThread().getFlumeLogInfList().size() == 0) {
                return;
            }
            String reqId = "", cid = "", pcid = "";
            if (StringUtil.hasText(rc.getReqId())) {
                reqId = rc.getReqId();
                cid = rc.getCid();
                pcid = rc.getPcid();
            } else {
                FlumeLogInf logInfo =
                    getLogThread().getFlumeLogInfList().get(getLogThread().getFlumeLogInfList().size() - 1);
                reqId = logInfo.getFlumeReqid();
                cid = logInfo.getFlumeCid();
                pcid = logInfo.getFlumePid();
            }
            FlumeLogInf logInfo =
                getLogThread().getFlumeLogInfList().get(getLogThread().getFlumeLogInfList().size() - 1);
            Long duration = 0L;
            if (logInfo.getPreMarkTime() != 0L) {
                duration = rc.getMarkTime() - logInfo.getPreMarkTime();
            }
            StringBuffer sb = new StringBuffer();
            if (!StringUtil.hasText(rc.getComponentId())) {
                // 2|ReqID|CID|PCID|ServiceID|MarkTime|MarkType|Duration##
                if (rc.getType().contains(CLIENT)) {
                    duration = rc.getMarkTime() - logInfo.getFlumeSerStTime();
                }
                sb.append(reqId).append(Constants.OR).append(cid).append(Constants.OR).append(null == pcid ? "" : pcid)
                    .append(Constants.OR).append(logInfo.getFlumeServiceId()).append(Constants.OR)
                    .append(rc.getMarkTime()).append(Constants.OR).append(rc.getType()).append(Constants.OR)
                    .append(duration).append("##");
                logFlume(Trace.MODULE_FLUME_NORMAL, Trace.LEVEL_F_NORMAL, "2", sb.toString());
            } else {
                // 1|ReqID|CID|PCID|ComponentID|MarkTime|MarkType|Duration|CallServiceID|CallAppID|CallIP|CallIDC|CallPort|CallUrl##
                sb.append(reqId).append(Constants.OR).append(cid).append(Constants.OR).append(null == pcid ? "" : pcid)
                    .append(Constants.OR).append(rc.getComponentId()).append(Constants.OR).append(rc.getMarkTime())
                    .append(Constants.OR).append(rc.getType()).append(Constants.OR).append(duration)
                    .append(Constants.OR).append(rc.getTargetSvcId()).append(Constants.OR).append(rc.getTargetAppId())
                    .append(Constants.OR).append(rc.getTargetIp()).append(Constants.OR).append(rc.getTargetIdc())
                    .append(Constants.OR).append(rc.getTargetPort()).append(Constants.OR).append(rc.getTargetUrl())
                    .append("##");
                logFlume(Trace.MODULE_FLUME_NORMAL, Trace.LEVEL_F_NORMAL, "1", sb.toString());
            }
            logInfo.setPreMarkTime(rc.getMarkTime());
        }

    }

    public void logFlumeSessionCreate(IFPSession session) {
        if (isDisable()) {
            return;
        }

        // add by wangzj@belink.com 主要解决SESSION发送FLUME数据量过大问题，仅当SESSION初始化时发送，而非定时发送
        if (!isPrintInitSessionInfo()) {
            return;
        }
        String flumeUserId = "";
        LogHandle logHandle = (LogHandle)SpringContextsUtil.getBean("logHandle");
        FlumeLogInf flumeLogInf = logHandle.getFlumeLogInf();
        if (null != flumeLogInf) {
            flumeUserId = null == flumeLogInf.getFlumeUserId() ? "" : flumeLogInf.getFlumeUserId();
        }
        // timeStamp|F_INIT|3|ReqIP|UserID|SessionID|REQMAC|DEVICEID|DEVICENAME|GROUPNAME|CREATETIME|DURATION##
        StringBuilder sb = new StringBuilder();
        sb.append(session.getAttribute(IFPSessionManager.CLIENT_IP)).append(Constants.OR)
            // userid
            .append(flumeUserId).append(Constants.OR).append(session.getId()).append(Constants.OR)
            .append(session.getAttribute(IFPSessionManager.CLIENT_MAC)).append(Constants.OR)
            .append(session.getAttribute(IFPSessionManager.DEVICE_ID)).append(Constants.OR)
            .append(session.getAttribute(IFPSessionManager.DEVICE_NAME)).append(Constants.OR).append(getSessionGroup())
            .append(Constants.OR).append(session.getCreateTime()).append(Constants.OR)
            .append(session.getLastAccessTime() - session.getCreateTime()).append("##");
        logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_INIT, "3", sb.toString());
    }

    /**
     * 打印flumeLogInfo
     * 
     * @param level 日志级别
     * @param flag 标记位 永不压缩
     * @param message 打印信息
     * @return
     */
    public void logFlume(int level, String flag, String message) {
        if (!isDisable()) {
            if (StringUtil.hasText(flag)) {
                message = flag + Constants.OR + (compress ? StringUtil.compress(message) : message);
            }
            // 打印日志
            Trace.log(Trace.MODULE_FLUME_NORMAL, level, message);
        }
    }

    /**
     * 打印flumeLogInfo
     * 
     * @param loggerName 日志名
     * @param level 日志级别
     * @param flag 标记位 永不压缩
     * @param message 打印信息
     */
    public void logFlume(String loggerName, int level, String flag, String message) {
        if (!isDisable()) {
            if (StringUtil.hasText(flag)) {
                message = flag + Constants.OR + (compress ? StringUtil.compress(message) : message);
            }
            // 打印日志
            Trace.log(loggerName, level, message);
        }
    }

    /**
     * 启动flume日志监控
     * 
     * @return
     */
    public void logFlumeQPSInit() {
        if (stainQPS % samplePeriod == 0) {
            sampleNum = stainQPS / samplePeriod;
        } else {
            sampleNum = (stainQPS / samplePeriod) + 1;
        }
        maxRequestSample = new MonitorFlumeSample();
        maxSvcSamples = new HashMap<String, MonitorFlumeSample>(0);
        maxCompSamples = new HashMap<String, MonitorFlumeSample>(0);
        Calendar calendar = Calendar.getInstance();
        Long time1 = calendar.getTimeInMillis();
        // 加1分钟
        calendar.add(Calendar.MINUTE, Constants.NUM_1);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH),
            calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), 0);
        Long time2 = calendar.getTimeInMillis();

        // 执行任务名称、开始执行时间、隔多久执行一次
        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder()
            .namingPattern("log-flume-qps-task-schedule-pool-%d").daemon(false).build());
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    // logFlumeQPS();
                    // logFlumeQPSMorePrecisely();
                } catch (Exception e) {
                    Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_ERROR, "flumeQPS() Exception", e);
                }
            }
        },
            // 1分钟后整分启动
            time2 - time1, this.samplePeriod, TimeUnit.MILLISECONDS);
    }

    /**
     * 更新最大耗时的样本集合
     */
    private void updateMaxDurationSample(Long nowTime, MonitorManager monitorManager) {
        // Trace.log(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_STAT, "updateMaxDurationSample:"+sampleCount.get());
        // 当前请求列表
        List<RequestInfo> totalRequestList = monitorManager.getTotalRequestList();
        // 当前服务请求集合
        Map<String, RequestMap> totalServiceRequestMap = monitorManager.getTotalServiceRequestMap();
        // 当前Action请求集合
        Map<String, RequestMap> totalActionRequestMap = monitorManager.getTotalActionRequestMap();
        StringBuilder sb = new StringBuilder();
        RequestMap requestMap;
        Map<String, RequestInfo> startTimeMap;
        // 总耗时
        Long totalTime = 0L;
        // 临时变量
        Long timeTemp = null;
        // 最短耗时信息
        RequestInfo requestInfoMin = new RequestInfo(null);
        // 最长耗时信息
        RequestInfo requestInfoMax = new RequestInfo(null);
        /*
         * 记录request并发信息    格式如下：
         * 0|IP|IDC|统计时间|总并发量|当前服务数|当前组件数|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时##
         */
        for (RequestInfo ri : totalRequestList) {
            if (timeTemp == null) {
                // 第一次循环
                requestInfoMin = ri;
                requestInfoMax = ri;
            }
            timeTemp = nowTime - ri.getStartTime();
            totalTime = totalTime + timeTemp;
            if (timeTemp < (nowTime - requestInfoMin.getStartTime())) {
                requestInfoMin = ri;
            } else if (timeTemp > (nowTime - requestInfoMax.getStartTime())) {
                requestInfoMax = ri;
            }
        }
        Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_INFO, "min.st==>{}, max.st==>{}", requestInfoMin.startTime,
            requestInfoMax.startTime);
        if (totalRequestList != null && totalRequestList.size() > 0) {
            if ((nowTime - requestInfoMax.getStartTime()) > maxRequestSample.getMaxDuration()) {
                maxRequestSample.setMaxDuration(nowTime - requestInfoMax.getStartTime());
                sb.append(Constants.OR).append(totalRequestList.size()).append(Constants.OR)
                    // 总并发量
                    .append(totalServiceRequestMap.size()).append(Constants.OR)
                    // 当前服务数
                    .append(totalActionRequestMap.size()).append(Constants.OR)
                    // 当前组件数
                    .append(totalTime / totalRequestList.size()).append(Constants.OR)
                    // 平均耗时
                    .append(requestInfoMax.getCId()).append(Constants.OR)
                    // 最大耗时cId getCId() = reqId|cId|pid|
                    .append(nowTime - requestInfoMax.getStartTime()).append(Constants.OR)
                    // 最大耗时
                    .append(requestInfoMin.getCId()).append(Constants.OR)
                    // 最小耗时cId
                    .append(nowTime - requestInfoMin.getStartTime())
                    // 最小耗时
                    .append("##");
                maxRequestSample.setFormattedStr(sb.toString());
            }
        }
        Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_INFO, "记录request并发信息 ok");
        /*
         * 记录service并发信息    格式如下：
         * 2|IP|IDC|统计时间##serviceId|并发量|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时#serviceId2|并发量|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时
         */
        totalTime = 0L;
        timeTemp = null;
        for (String serviceId : totalServiceRequestMap.keySet()) {
            // 某个服务的调用信息集合
            requestMap = totalServiceRequestMap.get(serviceId);
            // 某个服务的所有调用用者
            startTimeMap = requestMap.getStartTimeMap();
            for (String key : startTimeMap.keySet()) {
                RequestInfo ri = startTimeMap.get(key);
                if (timeTemp == null) {
                    // 第一次循环
                    requestInfoMin = ri;
                    requestInfoMax = ri;
                }
                timeTemp = nowTime - ri.getStartTime();
                totalTime = totalTime + timeTemp;
                if (timeTemp < (nowTime - requestInfoMin.getStartTime())) {
                    requestInfoMin = ri;
                } else if (timeTemp > (nowTime - requestInfoMax.getStartTime())) {
                    requestInfoMax = ri;
                }

            }
            if (startTimeMap != null && startTimeMap.size() > 0) {
                if (maxSvcSamples.containsKey(serviceId)) {
                    if ((nowTime - requestInfoMax.getStartTime()) > maxSvcSamples.get(serviceId).getMaxDuration()) {
                        maxSvcSamples.get(serviceId).setMaxDuration(nowTime - requestInfoMax.getStartTime());
                        sb.delete(0, sb.length());
                        sb.append("#")
                            .append(null == serviceNameMap.get(serviceId) ? serviceId : serviceNameMap.get(serviceId))
                            .append(Constants.OR).append(startTimeMap.size()).append(Constants.OR)
                            .append(totalTime / startTimeMap.size()).append(Constants.OR)
                            .append(requestInfoMax.getCId()).append(Constants.OR)
                            .append(nowTime - requestInfoMax.getStartTime()).append(Constants.OR)
                            .append(requestInfoMin.getCId()).append(Constants.OR)
                            .append(nowTime - requestInfoMin.getStartTime());
                        maxSvcSamples.get(serviceId).setFormattedStr(sb.toString());
                    }
                } else {
                    MonitorFlumeSample sample = new MonitorFlumeSample();
                    sample.setMaxDuration(nowTime - requestInfoMax.getStartTime());
                    sb.delete(0, sb.length());
                    sb.append("#")
                        .append(null == serviceNameMap.get(serviceId) ? serviceId : serviceNameMap.get(serviceId))
                        .append(Constants.OR).append(startTimeMap.size()).append(Constants.OR)
                        .append(totalTime / startTimeMap.size()).append(Constants.OR).append(requestInfoMax.getCId())
                        .append(Constants.OR).append(nowTime - requestInfoMax.getStartTime()).append(Constants.OR)
                        .append(requestInfoMin.getCId()).append(Constants.OR)
                        .append(nowTime - requestInfoMin.getStartTime());
                    sample.setFormattedStr(sb.toString());
                    maxSvcSamples.put(serviceId, sample);
                }
            }
        }
        Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_INFO, "记录service并发信息 ok");

        /*
         * 记录组件并发信息    格式如下：
         * 3|IP|IDC|统计时间##componentId|并发量|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时#componentId2|并发量|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时
         */
        totalTime = 0L;
        timeTemp = null;
        for (String componentId : totalActionRequestMap.keySet()) {
            // 某个服务的调用信息集合
            requestMap = totalActionRequestMap.get(componentId);
            // 某个服务的所有调用用者
            startTimeMap = requestMap.getStartTimeMap();
            for (String key : startTimeMap.keySet()) {
                RequestInfo ri = startTimeMap.get(key);
                if (timeTemp == null) {
                    // 第一次循环
                    requestInfoMin = ri;
                    requestInfoMax = ri;
                }
                timeTemp = nowTime - ri.getStartTime();
                totalTime = totalTime + timeTemp;
                if (timeTemp < (nowTime - requestInfoMin.getStartTime())) {
                    requestInfoMin = ri;
                } else if (timeTemp > (nowTime - requestInfoMax.getStartTime())) {
                    requestInfoMax = ri;
                }
            }
            if (startTimeMap != null && startTimeMap.size() > 0) {
                if (maxCompSamples.containsKey(componentId)) {
                    if ((nowTime - requestInfoMax.getStartTime()) > maxCompSamples.get(componentId).getMaxDuration()) {
                        maxCompSamples.get(componentId).setMaxDuration(nowTime - requestInfoMax.getStartTime());
                        sb.delete(0, sb.length());
                        sb.append("#")
                            .append(
                                null == actionNameMap.get(componentId) ? componentId : actionNameMap.get(componentId))
                            .append(Constants.OR).append(startTimeMap.size()).append(Constants.OR)
                            .append(totalTime / startTimeMap.size()).append(Constants.OR)
                            .append(requestInfoMax.getCId()).append(Constants.OR)
                            .append(nowTime - requestInfoMax.getStartTime()).append(Constants.OR)
                            .append(requestInfoMin.getCId()).append(Constants.OR)
                            .append(nowTime - requestInfoMin.getStartTime());
                        maxCompSamples.get(componentId).setFormattedStr(sb.toString());
                    }
                } else {
                    MonitorFlumeSample sample = new MonitorFlumeSample();
                    sample.setMaxDuration(nowTime - requestInfoMax.getStartTime());
                    sb.delete(0, sb.length());
                    sb.append("#")
                        .append(null == actionNameMap.get(componentId) ? componentId : actionNameMap.get(componentId))
                        .append(Constants.OR).append(startTimeMap.size()).append(Constants.OR)
                        .append(totalTime / startTimeMap.size()).append(Constants.OR).append(requestInfoMax.getCId())
                        .append(Constants.OR).append(nowTime - requestInfoMax.getStartTime()).append(Constants.OR)
                        .append(requestInfoMin.getCId()).append(Constants.OR)
                        .append(nowTime - requestInfoMin.getStartTime());
                    sample.setFormattedStr(sb.toString());
                    maxCompSamples.put(componentId, sample);
                }
            }
        }

        Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_INFO, "记录组件并发信息 ok");
    }

    /**
     * 并发量日志，包括session、request、service、component
     * 
     * @return
     */
    @Deprecated
    public void logFlumeQPS() throws Exception {

        /*
         * totalRequestList（size=10） = sessionRequestMap（size=3）：{session1(size=2),session2(size=1),session3(size=7)}
         * 3个session有10个请求，session1有2个请求，session2有1个请求，session3有7个请求
         * totalRequestList（size=10） = totalServiceRequestMap（size=3）：{service1(size=2),service2(size=1),service3(size=7)}
         * 3个服务有10个请求，service1有2个请求，service2有1个请求，service3有7个请求
         * totalRequestList（size=10） = totalActionRequestMap（size=3）：{action1(size=2),action2(size=8)}
         * 3个组件有10个请求，action1有2个请求，action2有8个请求
         * action数应该小于等于service数，应为一个action可以被多个service执行，当时service不能同时执行多个actiong
        */

        if (!isDisable()) {
            // 获取监控实例
            MonitorManager monitorManager = (MonitorManager)SpringContextsUtil.getBean(Constants.MONITOR_MANAGER);
            Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_DEBUG, "Get monitorManager");
            // 获取当前的监控的所有对象信息并返回当前时间
            Long nowTime = monitorManager.countRequest();
            Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_DEBUG, "Get CurTime: " + nowTime);
            // 当前请求列表
            List<RequestInfo> totalRequestList = monitorManager.getTotalRequestList();
            Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_DEBUG, "Get request list");
            // 当前session请求集合
            Map<String, RequestMap> sessionRequestMap = monitorManager.getSessionRequestMap();
            Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_DEBUG, "Get session list");
            // 当前服务请求集合
            Map<String, RequestMap> totalServiceRequestMap = monitorManager.getTotalServiceRequestMap();
            Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_DEBUG, "Get service list");
            // 当前Action请求集合
            Map<String, RequestMap> totalActionRequestMap = monitorManager.getTotalActionRequestMap();
            Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_DEBUG, "Get action list");
            StringBuffer sb = new StringBuffer();
            RequestMap requestMap;
            Map<String, RequestInfo> startTimeMap;
            // 总耗时
            Long totalTime = 0L;
            // 临时变量
            Long timeTemp = null;
            // 最短耗时信息
            RequestInfo requestInfoMin = new RequestInfo(null);
            // 最长耗时信息
            RequestInfo requestInfoMax = new RequestInfo(null);
            /*
             * 记录request并发信息    格式如下：
             * 0|IP|IDC|统计时间|总并发量|当前服务数|当前组件数|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时##
             */
            for (RequestInfo ri : totalRequestList) {
                if (timeTemp == null) {
                    // 第一次循环
                    requestInfoMin = ri;
                    requestInfoMax = ri;
                }
                timeTemp = nowTime - ri.getStartTime();
                totalTime = totalTime + timeTemp;
                if (timeTemp < (nowTime - requestInfoMin.getStartTime())) {
                    requestInfoMin = ri;
                } else if (timeTemp > (nowTime - requestInfoMax.getStartTime())) {
                    requestInfoMax = ri;
                }
            }
            sb.append(getAppName()).append(Constants.OR);
            sb.append(IpUtils.getHostAddress()).append(Constants.OR).append(idcId)
                // 统计时间
                .append(Constants.OR).append(nowTime);
            if (totalRequestList != null && totalRequestList.size() > 0) {
                sb.append(Constants.OR).append(totalRequestList.size()).append(Constants.OR)
                    // 总并发量
                    .append(totalServiceRequestMap.size()).append(Constants.OR)
                    // 当前服务数
                    .append(totalActionRequestMap.size()).append(Constants.OR)
                    // 当前组件数
                    .append(totalTime / totalRequestList.size()).append(Constants.OR)
                    // 平均耗时
                    .append(requestInfoMax.getCId()).append(Constants.OR)
                    // 最大耗时cId getCId() = reqId|cId|pid|
                    .append(nowTime - requestInfoMax.getStartTime()).append(Constants.OR)
                    // 最大耗时
                    .append(requestInfoMin.getCId()).append(Constants.OR)
                    // 最小耗时cId
                    .append(nowTime - requestInfoMin.getStartTime())
                    // 最小耗时
                    .append("##");
            } else { // 补充一条数据，表示并发量为0
                sb.append(Constants.OR)
                    // 总并发量
                    .append("0|")
                    // 当前服务数
                    .append("0|")
                    // 当前组件数
                    .append("0|")
                    // 平均耗时
                    .append("0|")
                    // 最大耗时cId
                    .append(Constants.OR)
                    // 最大耗时
                    .append("0|")
                    // 最小耗时cId
                    .append(Constants.OR)
                    // 最小耗时
                    .append("0##");
            }
            logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_STAT, "0", sb.toString());
            /*
             * 记录session并发信息    格式如下：
             * 1|APPID|IP|IDC|GROUP|MAXDURATION|MAXSESSIONID|MINDURATION|MINSESSIONID|AVGDURATION|统计时间|总并发量####sesstionId|DURATION#sesstionId2|DURATION
             * 注：并不是每个请求都有session的，应该是大部分请求都是无session
             */
            if (StringUtil.hasText(getSessionGroup())) {
                SessionManager sessionMgr = (SessionManager)SpringContextsUtil.getBean(Constants.SESSION_MANAGER);
                if (sessionMgr instanceof IFPSessionManager) {
                    Map<String, SessionElement> sessionMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                        SpringContextsUtil.getApplicationContext(), SessionElement.class, true, false);
                    List<IFPSession> allSessions = new ArrayList<IFPSession>();
                    for (SessionElement se : sessionMap.values()) {
                        List<IFPSession> sessLs =
                            ((IFPSessionManager)sessionMgr).getAllSessionFromCache(se.getCacheName());
                        if (null != sessLs) {
                            allSessions.addAll(sessLs);
                        }
                    }
                    if (allSessions.isEmpty()) {
                        logFlumeBlankSessionStat(nowTime);
                    } else {
                        Collections.sort(allSessions, sessionComparator);
                        Long totalDuration = 0L;
                        for (IFPSession s : allSessions) {
                            totalDuration += (s.getLastAccessTime() - s.getCreateTime());
                        }
                        Long avgDuration = totalDuration / allSessions.size();
                        IFPSession maxSession = allSessions.get(allSessions.size() - 1),
                            minSession = allSessions.get(0);
                        sb.delete(0, sb.length());
                        sb.append(getAppName()).append(Constants.OR).append(IpUtils.getHostAddress())
                            .append(Constants.OR).append(idcId).append(Constants.OR).append(getSessionGroup())
                            .append(Constants.OR).append(maxSession.getLastAccessTime() - maxSession.getCreateTime())
                            .append(Constants.OR).append(maxSession.getId()).append(Constants.OR)
                            .append(minSession.getLastAccessTime() - minSession.getCreateTime()).append(Constants.OR)
                            .append(minSession.getId()).append(Constants.OR).append(avgDuration).append(Constants.OR)
                            .append(nowTime).append(Constants.OR).append(allSessions.size()).append("####");
                        boolean firstElement = true;
                        for (IFPSession s : allSessions) {
                            if (!firstElement) {
                                sb.append("#");
                            } else {
                                firstElement = false;
                            }
                            sb.append(s.getId()).append(Constants.OR).append(s.getLastAccessTime() - s.getCreateTime());
                        }
                        logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_STAT, "1", sb.toString());
                    }

                } else {
                    logFlumeBlankSessionStat(nowTime);
                }
            }
            /*totalTime = 0L;
            timeTemp = null;
            sb.delete(0, sb.length());
            sb.append("1|")// 首位：0-request、1-session、2-service、3-component
              .append(localIp).append(Constants.OR)
              .append(idcId).append(Constants.OR)
              .append(nowTime).append(Constants.OR)// 统计时间
              .append(sessionRequestMap.size()).append("##"); // 总并发量
            for(String sessiongId : sessionRequestMap.keySet()){
            	requestMap = sessionRequestMap.get(sessiongId);
            	startTimeMap = requestMap.getStartTimeMap();// 某个session的所有调用用者
            	for(String key : startTimeMap.keySet()){
            		requestInfo = startTimeMap.get(key);
            		if(timeTemp==null){// 第一次循环
            			requestInfoMin = requestInfo;
            			requestInfoMax = requestInfo;
            		}
            		timeTemp = nowTime - requestInfo.getStartTime();
            		totalTime = totalTime + timeTemp;
            		if(timeTemp < (nowTime - requestInfoMin.getStartTime())){
            			requestInfoMin = requestInfo;
            		}else if(timeTemp > (nowTime - requestInfoMax.getStartTime())){
            			requestInfoMax = requestInfo;
            		}
            	}
            	
            	if(startTimeMap!=null && startTimeMap.size()>0){
            		sb.append("#")
            		  .append(sessiongId).append(Constants.OR)
            		  .append(startTimeMap.size()).append(Constants.OR)
            		  .append(totalTime/startTimeMap.size()).append("#")
            		  .append(requestInfoMax.getCId()).append(Constants.OR)
            		  .append(nowTime-requestInfoMax.getStartTime()).append("#")
            		  .append(requestInfoMin.getCId()).append(Constants.OR)
            		  .append(nowTime-requestInfoMin.getStartTime());
            	}
            	
            }
            if(sb.length()>=0){// 有数据时才打印
            	Trace.log(Trace.MODULE_FLUME, Trace.LEVEL_F_STAT, compress?StringUtil.compress(sb.toString()):sb.toString());
            }*/
            /*
             * 记录service并发信息    格式如下：
             * 2|IP|IDC|统计时间##serviceId|并发量|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时#serviceId2|并发量|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时
             */
            totalTime = 0L;
            timeTemp = null;
            sb.delete(0, sb.length());
            sb.append(getAppName()).append(Constants.OR);
            sb.append(IpUtils.getHostAddress()).append(Constants.OR).append(idcId)
                // 统计时间
                .append(Constants.OR).append(nowTime).append("#");
            for (String serviceId : totalServiceRequestMap.keySet()) {
                // 某个服务的调用信息集合
                requestMap = totalServiceRequestMap.get(serviceId);
                // 某个服务的所有调用用者
                startTimeMap = requestMap.getStartTimeMap();
                for (String key : startTimeMap.keySet()) {
                    RequestInfo ri = startTimeMap.get(key);
                    if (timeTemp == null) {
                        // 第一次循环
                        requestInfoMin = ri;
                        requestInfoMax = ri;
                    }
                    timeTemp = nowTime - ri.getStartTime();
                    totalTime = totalTime + timeTemp;
                    if (timeTemp < (nowTime - requestInfoMin.getStartTime())) {
                        requestInfoMin = ri;
                    } else if (timeTemp > (nowTime - requestInfoMax.getStartTime())) {
                        requestInfoMax = ri;
                    }

                }
                if (startTimeMap != null && startTimeMap.size() > 0) {
                    Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_INFO, "svcID:" + serviceId);
                    sb.append("#")
                        .append(null == serviceNameMap.get(serviceId) ? serviceId : serviceNameMap.get(serviceId))
                        .append(Constants.OR).append(startTimeMap.size()).append(Constants.OR)
                        .append(totalTime / startTimeMap.size()).append(Constants.OR).append(requestInfoMax.getCId())
                        .append(Constants.OR).append(nowTime - requestInfoMax.getStartTime()).append(Constants.OR)
                        .append(requestInfoMin.getCId()).append(Constants.OR)
                        .append(nowTime - requestInfoMin.getStartTime());
                }
            }
            if (totalServiceRequestMap == null || totalServiceRequestMap.size() == 0) { // 补充一条数据，表示并发量为0
                sb.append("#").append(Constants.OR).append("0|").append("0|").append(Constants.OR).append("0|")
                    .append(Constants.OR).append("0");
            }
            logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_STAT, "2", sb.toString());
            /*
             * 记录组件并发信息    格式如下：
             * 3|IP|IDC|统计时间##componentId|并发量|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时#componentId2|并发量|平均耗时|最大耗时cId|最大耗时|最小耗时cId|最小耗时
             */
            totalTime = 0L;
            timeTemp = null;
            sb.delete(0, sb.length());
            sb.append(getAppName()).append(Constants.OR);
            sb.append(IpUtils.getHostAddress()).append(Constants.OR).append(idcId)
                // 统计时间
                .append(Constants.OR).append(nowTime).append("#");
            for (String componentId : totalActionRequestMap.keySet()) {
                // 某个服务的调用信息集合
                requestMap = totalActionRequestMap.get(componentId);
                // 某个服务的所有调用用者
                startTimeMap = requestMap.getStartTimeMap();
                for (String key : startTimeMap.keySet()) {
                    RequestInfo ri = startTimeMap.get(key);
                    if (timeTemp == null) {
                        // 第一次循环
                        requestInfoMin = ri;
                        requestInfoMax = ri;
                    }
                    timeTemp = nowTime - ri.getStartTime();
                    totalTime = totalTime + timeTemp;
                    if (timeTemp < (nowTime - requestInfoMin.getStartTime())) {
                        requestInfoMin = ri;
                    } else if (timeTemp > (nowTime - requestInfoMax.getStartTime())) {
                        requestInfoMax = ri;
                    }
                }
                if (startTimeMap != null && startTimeMap.size() > 0) {
                    Trace.log(Trace.MODULE_MONITOR, Trace.LEVEL_INFO, "compID:" + componentId);
                    sb.append("#")
                        .append(null == actionNameMap.get(componentId) ? componentId : actionNameMap.get(componentId))
                        .append(Constants.OR).append(startTimeMap.size()).append(Constants.OR)
                        .append(totalTime / startTimeMap.size()).append(Constants.OR).append(requestInfoMax.getCId())
                        .append(Constants.OR).append(nowTime - requestInfoMax.getStartTime()).append(Constants.OR)
                        .append(requestInfoMin.getCId()).append(Constants.OR)
                        .append(nowTime - requestInfoMin.getStartTime());
                }
            }
            if (totalActionRequestMap == null || totalActionRequestMap.size() == 0) { // 补充一条数据，表示并发量为0
                sb.append("#").append(Constants.OR).append("0|").append("0|").append(Constants.OR).append("0|")
                    .append(Constants.OR).append("0");
            }
            logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_STAT, "3", sb.toString());
        }
    }

    private void logFlumeBlankSessionStat(Long nowTime) {
        StringBuilder sb = new StringBuilder();
        sb.append(getAppName()).append(Constants.OR).append(IpUtils.getHostAddress()).append(Constants.OR).append(idcId)
            .append(Constants.OR).append(getSessionGroup()).append(Constants.OR).append(0).append(Constants.OR)
            .append("").append(Constants.OR).append(0).append(Constants.OR).append("").append(Constants.OR).append(0)
            .append(Constants.OR).append(nowTime).append(Constants.OR).append(0).append("####").append("")
            .append(Constants.OR).append(0);
        logFlume(Trace.MODULE_FLUME_STAT, Trace.LEVEL_F_STAT, "1", sb.toString());
    }

    /**
     * 重要，当目前已经处在请求中，获取FlumeLog的cid，不能在入口如采用这个方法
     */
    public String getFlumeLogCid() {
        Map confMap = systemConf.getConfMap();
        StringBuffer sb = new StringBuffer();
        if (null != confMap) {
            // 取得机器标识
            String appCode = (String)confMap.get("appCode");
            if (null != appCode) {
                // 增加下划线，方便未来作为分隔符，取得应用名称 wangzj@belink.com
                return sb.append(idcId).append("-").append(IpUtils.getHostAddress()).append("-")
                    // .append(appCode)// crrentId已经有appcode，这里不需要再添加
                    // .append("-")
                    .append(getLogThread().getCurrentId()).toString();
            }
        }
        return sb.append(idcId).append("-").append(IpUtils.getHostAddress()).append("-")
            .append(getLogThread().getCurrentId()).toString();
    }

    /**
     * 重要，当目前已经处在请求中，获取FlumeLog的reqid，不能在入口如采用这个方法
     */
    public String getFlumeLogReqId() {
        Map confMap = systemConf.getConfMap();
        StringBuffer sb = new StringBuffer();
        if (null != reqIdGenerator) {
            return reqIdGenerator.generatId();
        }

        if (null != confMap) {
            // 取得机器标识
            String appCode = (String)confMap.get("appCode");
            if (null != appCode) {
                // 增加下划线，方便未来作为分隔符，取得应用名称 wangzj@belink.com
                return sb.append(idcId).append("-").append(IpUtils.getHostAddress()).append("-")
                    // .append(appCode)// rootId已经有appcode，这里不需要再添加
                    // .append("-")
                    .append(getLogThread().getRootId()).toString();
            }
        }

        return sb.append(idcId).append("-").append(IpUtils.getHostAddress()).append("-")
            .append(getLogThread().getRootId()).toString();
    }

    /**
     * 获取服务映射
     * 
     * @return Integer
     */
    public String getServiceMapping(String serName) {
        return this.serviceNameMap.get(serName);
    }

    /**
     * 获取组件映射
     * 
     * @return Integer
     */
    public String getActionMapping(String actionName) {
        if (actionNameMap != null) {
            return this.actionNameMap.get(actionName);
        } else {
            return null;
        }
    }

    public FlumeLogInf getFlumeLogInf() {
        if (getLogThread().getFlumeLogInfList().size() > 0) {
            return getLogThread().getFlumeLogInfList().get(getLogThread().getFlumeLogInfList().size() - 1);
        }
        return null;
    }

    public void getFlumeLogInfToMap(Map<String, Object> map) {
        LogThread logThread = getLogThread();
        if (logThread.getFlumeLogInfList().size() > 0) {
            FlumeLogInf logInfo = logThread.getFlumeLogInfList().get(logThread.getFlumeLogInfList().size() - 1);
            map.put(Constants.FLUMEREQIP, logInfo.getFlumeReqIP());
            map.put(Constants.FLUMEREQID, logInfo.getFlumeReqid());
            map.put(Constants.FLUMEPID, logInfo.getFlumeCid());
        }
    }

    public void getFlumeLogInfToDataMap(DataMap dataMap) {
        LogThread logThread = getLogThread();
        if (logThread.getFlumeLogInfList().size() > 0) {
            FlumeLogInf logInfo = logThread.getFlumeLogInfList().get(logThread.getFlumeLogInfList().size() - 1);
            dataMap.put(Constants.FLUMEREQIP, logInfo.getFlumeReqIP());
            dataMap.put(Constants.FLUMEREQID, logInfo.getFlumeReqid());
            dataMap.put(Constants.FLUMEPID, logInfo.getFlumeCid());
        }
    }

    public SystemConf getSystemConf() {
        return systemConf;
    }

    public void setSystemConf(SystemConf systemConf) {
        this.systemConf = systemConf;
    }

    public String getIdcId() {
        return idcId;
    }

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    public void setIdcId(String idcId) {
        this.idcId = idcId;
    }

    public int getStainQPS() {
        return stainQPS;
    }

    public void setStainQPS(int stainQPS) {
        this.stainQPS = stainQPS;
    }

    public boolean getCompress() {
        return compress;
    }

    public void setCompress(boolean compress) {
        this.compress = compress;
    }

    public void setServiceNameMap(Map<String, String> serviceNameMap) {
        this.serviceNameMap = serviceNameMap;
    }

    public void setActionNameMap(Map<String, String> actionNameMap) {
        this.actionNameMap = actionNameMap;
    }

    public boolean isPrintRemote() {
        return printRemote;
    }

    public void setPrintRemote(boolean printRemote) {
        this.printRemote = printRemote;
    }

    public boolean isSimplifiedSvcInfo() {
        return simplifiedSvcInfo;
    }

    public void setSimplifiedSvcInfo(boolean simplifiedSvcInfo) {
        this.simplifiedSvcInfo = simplifiedSvcInfo;
    }

    public boolean isDisable() {
        return disable;
    }

    public void setDisable(boolean disable) {
        this.disable = disable;
    }

    public IKeyGenerator getReqIdGenerator() {
        return reqIdGenerator;
    }

    public void setReqIdGenerator(IKeyGenerator reqIdGenerator) {
        this.reqIdGenerator = reqIdGenerator;
    }

    public boolean isPrintDBSvcInfo() {
        return printDBSvcInfo;
    }

    public void setPrintDBSvcInfo(boolean printDBSvcInfo) {
        this.printDBSvcInfo = printDBSvcInfo;
    }

    public boolean isPrintSISvcInfo() {
        return printSISvcInfo;
    }

    public void setPrintSISvcInfo(boolean printSISvcInfo) {
        this.printSISvcInfo = printSISvcInfo;
    }

    public boolean isPrintRPCSvcInfo() {
        return printRPCSvcInfo;
    }

    public void setPrintRPCSvcInfo(boolean printRPCSvcInfo) {
        this.printRPCSvcInfo = printRPCSvcInfo;
    }

    public boolean isPrintCacheSvcInfo() {
        return printCacheSvcInfo;
    }

    public void setPrintCacheSvcInfo(boolean printCacheSvcInfo) {
        this.printCacheSvcInfo = printCacheSvcInfo;
    }

    public String getSessionGroup() {
        return sessionGroup;
    }

    public void setSessionGroup(String sessionGroup) {
        this.sessionGroup = sessionGroup;
    }

    public int getSamplePeriod() {
        return samplePeriod;
    }

    public void setSamplePeriod(int samplePeriod) {
        this.samplePeriod = samplePeriod;
    }

    public void setServiceDescMap(Map<String, String> serviceDescMap) {
        this.serviceDescMap = serviceDescMap;
    }

    public void setActionDescMap(Map<String, String> actionDescMap) {
        this.actionDescMap = actionDescMap;
    }

    public boolean isPrintInitSessionInfo() {
        return printInitSessionInfo;
    }

    public void setPrintInitSessionInfo(boolean printInitSessionInfo) {
        this.printInitSessionInfo = printInitSessionInfo;
    }

    public String getCallId() {
        return generateCallId();
    }

}
